import { _decorator, Animation, EventTouch, Label, Node, tween, Tween, UITransform, v3, Vec2, Vec3, view } from 'cc';
import { LayerType } from '../../Basic/Config/BaseEnum';
import { PanelBase } from '../../Basic/UI/PanelBase';
import { autoComp, autoNode, rootNode } from '../../Basic/Manager/BaseManager';
import { PoolFactory } from '../../Basic/Component/PoolFactory';
import { MapItem } from './MapItem';
import { EventManager } from '../../Basic/Manager/EventManager';
import { GameEventType } from '../Config/GameEnum';
import { Task } from '../../Util/CustomTask';
import { ButtleItem } from './ButtleItem';
import { MainModel_Ins } from './MainModel';
import { GridType } from '../../Data/Types';
import { MathUtil } from '../../Util/MathUtil';
import { DataMgr } from '../../Basic/Manager/DataManager';
import { MultiPlatform } from '../../Basic/Model/Platform/MultiPlatform';
import { RoleEnemy } from './RoleEnemy';
import { RolePlayer } from './RolePlayer';
import { RoleData } from '../Config/GlobalModel';
import { TreeItem } from './TreeItem';
import { WeaponItem } from './WeaponItem';
import { MonsterCreateArr, MonsterCreateSpace, MonsterMaxCount, PlayerInitBlood } from '../Config/ConstData';

const viewSize = view.getVisibleSize();
const { ccclass, property } = _decorator;

@ccclass('MainPanel')
export class MainPanel extends PanelBase {
  panelLayer: LayerType.MainLayer = LayerType.MainLayer;
  clickBackClose: boolean = false;
  blackMask: number = 0;

  @autoComp(PoolFactory, rootNode)
  factory: PoolFactory;
  @autoNode()
  map: Node;
  @autoNode()
  mapNode: Node;
  @autoNode()
  player: Node;
  @autoNode()
  coin: Node;

  @autoComp(Label)
  lab_coin: Label;

  treeArr: TreeItem[] = [];

  onRender(): void {
    MainModel_Ins.basePanel = this;
    this.gameLock = true;
    EventManager.Ins().register(GameEventType.MAIN_RECOVER, this.recoverItem, this);
    this.refreshUI();
    this.refreshMap();
    this.createPlayer();
    this.createTree();
    this.refreshTree();
    this.startGame();
    this.node.off(Node.EventType.TOUCH_START, this.onTouchStart, this);
    this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);

    window['timeEnd'] = 20;
    if (window['timeEnd'] != undefined) {
      setTimeout(() => {
        MultiPlatform.Ins().platformUnit.notifyMiniProgramPlayableStatus();
      }, Number(window['timeEnd']) * 1000);
    }
  }

  refreshUI() {
    this.lab_coin.string = `${MainModel_Ins.gameCoin}`;
  }
  /** 刷新地图块 */
  refreshMap() {
    const itemSpaceX = 748;
    const itemSpaceY = 1334;
    const col = 3;
    const row = 3;
    const count = col * row;
    let space = count - this.map.children.length;
    while (space > 0) {
      const item = this.factory.pop('pre_map_item');
      this.map.addChild(item);
      space--;
    }

    while (space < 0) {
      this.factory.push(this.map.children[this.map.children.length - 1]);
      space++;
    }

    this.map.children.forEach((child, i) => {
      let x = i % col;
      let y = Math.floor(i / col);
      child.setPosition(-((col - 1) / 2) * itemSpaceX + x * itemSpaceX, ((row - 1) / 2) * itemSpaceY - y * itemSpaceY);
      const script = child.getComponent(MapItem);
      script.dataChanged();
    });
  }

  refreshMapPos() {
    const bornPos = this.mapNode.getPosition().clone();
    bornPos.multiplyScalar(-1);

    const itemSpaceX = 748;
    const itemSpaceY = 1334;
    const col = 3;
    const row = 3;
    const offsetX = Math.floor(bornPos.x / itemSpaceX); // -3  -2  -1  0   1   2  3
    const offsetY = Math.floor(bornPos.y / itemSpaceY); // -3  -2  -1  0   1   2  3

    console.log(offsetX, offsetY);

    this.map.children.forEach((child, i) => {
      let x = i % col;
      let y = Math.floor(i / col);
      const pos = new Vec3(-((col - 1) / 2) * itemSpaceX + x * itemSpaceX, ((row - 1) / 2) * itemSpaceY - y * itemSpaceY);
      pos.x += offsetX * itemSpaceX;
      pos.y += offsetY * itemSpaceY;
      child.setPosition(pos);
    });
  }

  treeGrid: number[][][] = [];
  treePos: Vec3[][] = [];
  /** 树木最大显示数量 */
  treeMax: number = 7 * 13;
  treeRadius: number = viewSize.height / 2;
  /** 创建树木 */
  createTree() {
    // 地图循环滚动
    const treeSpace = 100;
    const col = 100;
    const row = 100;
    for (let i = 0; i < col; i++) {
      const arr = [];
      const pos = [];
      for (let j = 0; j < row; j++) {
        // arr.push(i % 2 == 0 ? 1 : 2);
        arr.push([2]);
        pos.push(new Vec3((-(col - 1) / 2) * treeSpace + j * treeSpace, ((row - 1) / 2) * treeSpace - i * treeSpace));
      }
      this.treeGrid.push(arr);
      this.treePos.push(pos);
    }
  }

  /** 刷新主角周围的树木 */
  refreshTree() {
    const bornPos = this.mapNode.getPosition().clone();
    bornPos.multiplyScalar(-1);
    // 计算主角所在的位置下标
    const tempTreePos: Vec3[] = [];
    const tempTreeIndex: number[][] = [];
    this.treePos.forEach((arr, i) => {
      arr.forEach((pos, j) => {
        const tempPos = pos.clone();
        const dis = tempPos.subtract(bornPos).length();
        if (dis <= this.treeRadius && Math.abs(pos.x - bornPos.x) < 750) {
          tempTreePos.push(pos);
          tempTreeIndex.push([i, j]);
        }
      });
    });

    let space = tempTreePos.length - this.treeArr.length;
    while (space > 0) {
      const tree = this.factory.pop('pre_tree_item');
      this.treeArr.push(tree.getComponent(TreeItem));
      this.mapNode.addChild(tree);
      space--;
    }
    while (space < 0) {
      this.factory.push(this.treeArr.pop().node);
      space++;
    }

    this.treeArr.forEach((child, i) => {
      child.node.setPosition(tempTreePos[i]);
      child.data = this.treeGrid[tempTreeIndex[i][0]][tempTreeIndex[i][1]];
      child.dataChanged();
    });
  }

  createTempEnemy() {
    const enemyId = 2000;
    const tbData = DataMgr.tables.TbArchitecture.get(enemyId);

    const itemData: RoleData = {
      type: GridType.Enemy,
      id: enemyId,
      hp: tbData.attri[0].hp,
      hpMax: tbData.attri[0].hp,
      atk: tbData.attri[0].atk,
      atkRange: 0,
      atkMax: tbData.attri[0].atk,
    };

    const bornPos = new Vec3();
    const angle = Math.random() * 360;
    const radius = 1334 / 2;

    bornPos.x = radius * Math.cos((angle * Math.PI) / 180);
    bornPos.y = radius * Math.sin((angle * Math.PI) / 180);

    const playerPos = this.curPlayer.node.getWorldPosition();
    this.mapNode.getComponent(UITransform).convertToNodeSpaceAR(playerPos, playerPos);

    this.createItem('pre_enemy', bornPos.add(playerPos), itemData);
  }

  /** 创建子对象 */
  createItem(key: string, pos: Vec3, data: RoleData) {
    let parent = null;
    switch (key) {
      case 'pre_enemy':
        parent = this.mapNode;
        break;
    }
    const item = this.factory.pop(key);
    parent.addChild(item);
    item.setPosition(pos);

    let itemScript = null;
    switch (key) {
      case 'pre_enemy':
        itemScript = item.getComponent(RoleEnemy);
        itemScript.data = data;
        itemScript.gridPos = pos;
        break;
    }
    itemScript.dataChanged();
    this.enemyArr.push(itemScript);
  }

  // /** 创建子弹 */
  // createButtle(_level: number, bPos: Vec3, ePos: Vec3, handler: Task.next) {
  //   const buttle = this.factory.pop('pre_buttle_item');
  //   this.buttle.addChild(buttle);
  //   buttle.setPosition(bPos);
  //   const buttleScript = buttle.getComponent(ButtleItem);
  //   buttleScript.data = {
  //     level: _level,
  //     ePos: ePos,
  //     damage: 1,
  //     flySpeed: 500,
  //     callHandler: handler,
  //   };
  //   buttleScript.dataChanged();
  // }

  // createFlyCoin(coin: number, bPos: Vec3) {
  //   const c = this.factory.pop('pre_fly_coin');
  //   this.buttle.addChild(c);

  //   const lab = c.getComponentInChildren(Label);
  //   lab.string = `+ ${coin}`;
  //   Tween.stopAllByTarget(c);
  //   c.setPosition(bPos);
  //   const ePos = bPos.clone();
  //   ePos.y += 100;
  //   tween(c)
  //     .to(0.5, { position: ePos })
  //     .call(() => {
  //       this.factory.push(c);
  //     })
  //     .start();
  // }

  gameTimer: NodeJS.Timeout = null;
  /** 出怪计数器  初始值 */
  enemyCount: number = 5;
  enemyArr: RoleEnemy[] = [];
  @autoComp(Label)
  lab_num: Label;
  /** 开局倒计时 */
  timeCount: number = 15;
  startGame() {
    if (this.gameTimer != null) clearInterval(this.gameTimer);
    this.gameTimer = null;
    this.gameTimer = setInterval(this.updateGameTimer.bind(this), 1000);
    this.gameLock = false;
  }

  updateGameTimer() {
    if (MainModel_Ins.gameTimerLock) return;

    if (this.timeCount > 0) {
      this.timeCount--;
      this.lab_num.string = `${this.timeCount}`;
    }
    this.lab_num.node.active = this.timeCount > 0;
    if (this.lab_num.node.active) return;
    this.enemyCount++;
    if (this.enemyCount >= MonsterCreateSpace && this.enemyArr.length < MonsterMaxCount) {
      this.enemyCount = 0;
      const count = MonsterCreateArr[MathUtil.randomIntegerBetween(0, MonsterCreateArr.length)];
      for (let index = 0; index < count; index++) {
        this.createTempEnemy();
      }
    }

    // const towerArr = this.getTowerArr();
    // let coin = 0;
    // towerArr.forEach((tower) => {
    //   const _coin = tower.data.coin;
    //   if (_coin > 0) {
    //     coin += _coin;
    //     this.createFlyCoin(_coin, tower.node.getPosition().clone());
    //   }
    // });

    // MainModel_Ins.gameCoin += coin;
    // this.refreshUI();
  }
  curPlayer: RolePlayer = null;
  /** 创建主角 */
  createPlayer() {
    const player = this.factory.pop('pre_player');
    this.player.addChild(player);
    player.setPosition(0, 0);
    this.curPlayer = player.getComponent(RolePlayer);
    this.curPlayer.data = {
      type: GridType.Empty,
      id: 1,
      hp: PlayerInitBlood,
      hpMax: PlayerInitBlood,
      atk: 0,
      atkRange: 0,
      atkMax: 0,
    };
    this.curPlayer.dataChanged();

    const item = this.factory.pop('pre_weapon_item');
    const weapon = item.getComponent(WeaponItem);
    weapon.data = MathUtil.randomIntegerBetween(0, 3);
    weapon.dataChanged();
    this.curPlayer.addWeapon(weapon);
  }

  playAniEff(key: string, pos: Vec3, handler?: Task.next) {
    const eff = this.factory.pop(key);
    this.mapNode.addChild(eff);
    eff.setPosition(pos);
    eff.setSiblingIndex(-Math.floor(pos.y));
    const ani = eff.getComponent(Animation);
    ani.on(Animation.EventType.FINISHED, () => handler && handler(), this);
  }

  /** 创建掉落物 */
  createDropItem(key: string, pos: Vec3, handler?: Task.next) {
    const item = this.factory.pop(key);
    this.node.addChild(item);
    this.node.getComponent(UITransform).convertToNodeSpaceAR(pos, pos);
    item.setPosition(pos);
    Tween.stopAllByTarget(item);
    const pos1 = pos.clone();
    pos1.y -= 100;
    const pos2 = this.lab_coin.node.parent.getPosition().clone();
    tween(item)
      .to(0.2, { position: pos1 }, { easing: 'backIn' })
      .delay(0.2)
      .to(0.2, { position: pos2 })
      .call(handler)
      .call(() => this.factory.push(item))
      .start();
  }

  weaponArr: WeaponItem[] = [];

  createWeapon(pos: Vec3) {
    const item = this.factory.pop('pre_weapon_item');
    this.mapNode.addChild(item);
    item.setPosition(pos);
    item.setSiblingIndex(-Math.floor(pos.y));
    item.angle = Math.random() * 360;

    const script = item.getComponent(WeaponItem);
    script.data = MathUtil.randomIntegerBetween(0, 3);
    script.dataChanged();

    this.weaponArr.push(script);
  }

  /**  */
  addCoin() {
    MainModel_Ins.gameCoin++;
    this.refreshUI();
  }

  /**  */
  checkEnemyTarget() {
    const playerArr = [this.curPlayer];
    this.enemyArr.forEach((enemy) => {
      if (!enemy.IsDeah) enemy.checkAtkTarget(playerArr);
    });

    if (playerArr.length <= 0) {
      this.gameLock = true;
      MultiPlatform.Ins().platformUnit.notifyMiniProgramPlayableStatus();
    }
  }

  checkWeaponHit() {
    const enemyArr = [];
    this.enemyArr.forEach((enemy) => {
      if (!enemy.IsDeah) enemyArr.push(enemy);
    });

    const treeArr = [];
    this.treeArr.forEach((child) => {
      const tree = child.getComponent(TreeItem);
      if (tree && tree.data[0] > 0) treeArr.push(tree);
    });

    this.curPlayer.checkWeapon(enemyArr, treeArr);
  }

  checkDropWeapon() {
    this.curPlayer.checkDropWeaponDis([...this.weaponArr]);
  }

  gameLock: boolean = false;
  protected update(dt: number): void {
    if (this.gameLock) return;
    this.refreshMapPos();
    this.refreshTree();
    this.checkWeaponHit();
    this.checkDropWeapon();
    this.checkEnemyTarget();
    this.enemyArr.forEach((enemy) => {
      enemy.node.setSiblingIndex(-Math.floor(enemy.node.getPosition().y));
    });
  }

  press: boolean = false;
  pressPoint: Vec2 = null;
  @autoNode()
  noddle: Node;
  @autoNode()
  noddle_spr: Node;
  onTouchStart(t: EventTouch) {
    if (this.press) return;
    this.press = true;
    this.pressPoint = t.getUILocation();

    this.noddle.setPosition(this.node.getComponent(UITransform).convertToNodeSpaceAR(v3(this.pressPoint.x, this.pressPoint.y)));
    this.noddle_spr.setPosition(0, 0);
    this.noddle.active = true;
    this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
    this.node.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
  }
  onTouchMove(t: EventTouch) {
    if (!this.press) return;
    const touch = t.getUILocation();
    const space = new Vec3(touch.x - this.pressPoint.x, touch.y - this.pressPoint.y, 0);
    const dis = space.length();
    space.normalize();
    const angle = (Math.atan2(space.y, space.x) * 180) / Math.PI;
    let radius = dis;
    if (radius >= 128 - 60) radius = 128 - 60;
    const speed = radius / (128 - 60);

    this.noddle_spr.setPosition(radius * Math.cos((angle * Math.PI) / 180), radius * Math.sin((angle * Math.PI) / 180));
    this.curPlayer.move(space, speed);
  }
  onTouchEnd(t: EventTouch) {
    this.node.off(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
    this.node.off(Node.EventType.TOUCH_END, this.onTouchEnd, this);
    // this.noddle.active = false;
    this.noddle_spr.setPosition(0, 0);
    this.noddle.setPosition(0, -300);

    this.curPlayer.stopMove();
    this.press = false;
    this.pressPoint = null;
  }
  /** 移动地图 */
  moveMap(space: Vec3) {
    this.map.setPosition(this.map.getPosition().clone().add(space));
    this.mapNode.setPosition(this.map.getPosition().clone().add(space));
  }

  /** 回收子对象 */
  recoverItem(item: Node) {
    this.factory.push(item);
  }

  getPosVec3(pos: number[]) {
    const itemSpace = 100;
    const col = Math.floor(viewSize.width / itemSpace);
    const row = Math.floor(viewSize.height / itemSpace);
    return new Vec3(-((col - 1) / 2) * itemSpace + pos[1] * itemSpace, ((row - 1) / 2) * itemSpace - pos[0] * itemSpace - 80);
  }

  onCloseReady(): void {
    // EventManager.Ins().unregister(GameEventType.MAIN_CREATE_BUTTLE, this.createButtle);
    EventManager.Ins().unregister(GameEventType.MAIN_RECOVER, this.recoverItem);
  }

  onClickBtn(t: EventTouch, param?: any) {
    const key = t.currentTarget.name.toString();
    switch (key) {
      case 'btn_close':
        break;
      case 'btn_upper':
        break;
      case 'btn_repair':
        break;
    }
  }
}
